r"""Limiter functions.

Most limiter functions are a function of one argument :math:`\theta`,
called the flow parameter. This flow parameter is a quantity that is
known to change across a particular wave and this change is used to
determine the ammount of limiting for a wave.

"""

def minmod(a, b):
    r"""The minimod function of two arguments defined by:

    .. math::

        minmod(a, b) = \begin{cases}
                        a & if |a| < |b| and ab > 0 \\
                        b & if |b| < |a| and ab > 0 \\
                        0 & if ab < 0
                        \end{cases}

    """
    if (a*b) < 0:
        return 0.0
    else:
        return min( abs(a), abs(b) )

def maxmod(a, b):
    r"""The maxmod function of two arguments defined by:

    .. math::

        maxmod(a, b) = \begin{cases}
                        a & if |a| > |b| and ab > 0 \\
                        b & if |b| > |a| and ab > 0 \\
                        0 & if ab < 0
                        \end{cases}

    """
    if (a*b) < 0:
        return 0.0
    else:
        return max( abs(a), abs(b) )

class Limiter(object):
    """Base class for all limiter functions."""
    def limit(self, theta):
        pass

class UpwindLimiter(Limiter):
    r"""Limiter function for the first order upwind method.

    The function is given by:

    .. math::

        \phi(\theta) = 0

    Note that this effectvely does not apply any high order correction
    terms to the conservative update formula.

    """ 
    def limit(self, theta):
        return 0.0

class LaxWendroffLimiter(Limiter):
    r"""Limiter function for the Lax Wendroff method.

    The function is given by:

    .. math::

        \phi(\theta) = 1.0

    """ 
    def limit(self, theta):
        return 1.0

class BeamWarmingLimiter(Limiter):
    r"""Limiter function for the Beam Warming method given by:

    .. math::

        \phi(\theta) = \theta

    """ 
    def limit(self, theta):
        return theta

class FrommLimiter(Limiter):
    r"""Limiter function for the Beam Warming method given by:

    .. math::

        \phi(\theta) = 0.5 * (1 + theta)

    """ 
    def limit(self, theta):
        return 0.5  * (1 + theta)

class MinModLimiter(Limiter):
    r"""The minimod limiter function given by:

    .. math::

        \phi(\theta) = minmod(1, \theta)

    """
    def limit(self, theta):
        return minmod(1.0, theta)

class SuperbeeLimiter(Limiter):
    r"""The superbee limiter function given by:

    .. math::

        \phi(\theta) = max(0, min(1, 2\theta), min(2, \theta))

    """
    def limit(self, theta):
        return max(0, min(1, 2*theta), min(2, theta))

class MCLimiter(Limiter):
    r"""The mc limiter function given by:


    .. math::

        \phi(\theta) = max(0, min( \frac{1 + \theta}{2}, 2, 2\theta))

    """
    def limit(self, theta):
        return max(0, min(0.5*(1 + theta), 2, 2*theta))

class vanLeerLimiter(Limiter):
    r"""The van Leer limiter function given by:

    .. math::

        \phi(\theta) = \frac{\theta + |\theta|}{1 + |\theta|}

    """
    def limit(self, theta):
        atheta = abs(theta)
        return (theta + atheta)/(1.0 + atheta)

limiter_functions = [
    ('Upwind (default)', UpwindLimiter),
    ('LaxWendroff', LaxWendroffLimiter),
    ('BeamWarming', BeamWarmingLimiter),
    ('Fromm', FrommLimiter),
    ('MinMod', MinModLimiter),
    ('Superbee', SuperbeeLimiter),
    ('MC', MCLimiter),
    ('vanLeer', vanLeerLimiter)

    ]
                     
